           package com.java.diagnostics.visualizer.postprocessor.vgc.analysis;
           
           import com.java.diagnostics.visualizer.data.AggregateData;
           import com.java.diagnostics.visualizer.data.DataPoint;
           import com.java.diagnostics.visualizer.data.DataSet;
           import com.java.diagnostics.visualizer.data.TupleData;
           import com.java.diagnostics.visualizer.data.TupleDataBuilder;
           import com.java.diagnostics.visualizer.data.Variant;
           import com.java.diagnostics.visualizer.data.axes.AxisPair;
           import com.java.diagnostics.visualizer.factory.DataFactory;
           import com.java.diagnostics.visualizer.gc.defaultextensions.util.Messages;
           import com.java.diagnostics.visualizer.impl.factory.LogFactory;
           import com.java.diagnostics.visualizer.metadata.TupleMetaData;
           import com.java.diagnostics.visualizer.metadata.TupleMetaData.TableType;
           import com.java.diagnostics.visualizer.parser.vgc.constants.HiddenVGCLabels;
           import com.java.diagnostics.visualizer.postprocessing.PostProcessor;
           import com.java.diagnostics.visualizer.properties.OutputProperties;
           import java.text.MessageFormat;
           import java.util.logging.Logger;
           
           public class RollingAveragesPostProcessor
             implements PostProcessor
           {
             private final String className = getClass().getName();
           
             private static final Logger TRACE = LogFactory.getTrace(RollingAveragesPostProcessor.class);
           
             private static final String CALCULATED_DATA = Messages.getString("DerivedVGCDataPostProcessor.calculated.data.comment");
           
             private static final DataFactory hiddenFactory = DataFactory.getFactory(DataFactory.HIDDEN);
           
             private static String[] tuples = { "VGCLabels.live.heap.after.global.gc", 
               "VGCLabels.amount.freed", "VGCLabels.live.normal.heap.after.gc" };
           
             private static int windowLength = 50;
           
             private static final String ROLLING_AVERAGE_DISPLAY = Messages.getString("RollingAveragesPostProcessor.rolling.average.display");
           
             public void postprocess(DataSet dataSet, OutputProperties properties)
             {
               TRACE.entering(this.className, "postprocess");
               calculateRollingAverages(dataSet);
           
               Variant[] variants = dataSet.getVariants();
           
               for (int i = 0; i < variants.length; i++) {
                 calculateRollingAverages(variants[i]);
               }
               TRACE.exiting(this.className, "postprocess");
             }
           
             private void calculateRollingAverages(AggregateData data) {
               for (String tupleName : tuples) {
                 TupleData tuple = data.getTupleData(tupleName);
                 if ((tuple != null) && (!tuple.isEmpty())) {
                   DataPoint[] dataPoints = tuple.getDataPoints();
                   if (dataPoints.length < windowLength) {
                     return;
                   }
                   AxisPair averageAxisPair = tuple.getAxisPair();
           
                   String label = HiddenVGCLabels.ROLLING_AVERAGE + " " + tupleName;
                   String displayName = MessageFormat.format(
                     ROLLING_AVERAGE_DISPLAY, new Object[] { Messages.getString(tupleName) });
                   TupleDataBuilder averageTuple = hiddenFactory.createTupleData(
                     label, displayName, averageAxisPair);
           
                   averageTuple.setTupleMetaData(new TupleMetaData(TupleMetaData.TableType.NONE, 
                     null));
           
                   int start = 0;
                   int finish = windowLength;
           
                   double average = 0.0D;
                      double total = 0.0D;
           
                      for (int i = start; i < finish; i++) {
                        total += dataPoints[i].getRawY();
                   }
                      average = total / windowLength;
           
                      averageTuple.addDataPoint(
                        dataPoints[(finish / 2)].getSequenceUID(), dataPoints[(finish / 2)].getRawX(), 
                        average, CALCULATED_DATA);
           
                      for (int i = 0; i < dataPoints.length - windowLength; i++) {
                        total -= dataPoints[i].getRawY();
                        total += dataPoints[(finish + i)].getRawY();
                        average = total / windowLength;
                        averageTuple.addDataPoint(
                          dataPoints[(finish / 2 + i)].getSequenceUID(), 
                          dataPoints[(finish / 2 + i)].getRawX(), average, CALCULATED_DATA);
                   }
           
                      data.add(averageTuple);
                 }
               }
             }
           }

